package cc.minos.game
{
	import cc.minos.event.EventProxy;
	import cc.minos.game.evnets.Match3Event;
	import cc.minos.game.GridGame;
	import cc.minos.game.Piece;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	
	/**
	 * ...
	 * 对对碰
	 * @since 2012/11/28
	 * @version 1.0
	 * @author Minos
	 */
	public class Match3 extends GridGame
	{
		//储存第一次点击
		private var firstPiece:Piece;
		//是否移动
		private var isSwapping:Boolean;
		//是否下落
		private var isDropping:Boolean;
		
		/**
		 * 对对碰构造函数
		 * @param	continer	:	容器
		 * @param	cols		:	纵
		 * @param	rows		:	横
		 * @param	spacing		:	间隔
		 * @param	pieceClass	:	方块类
		 */
		public function Match3( continer:Sprite , cols:int , rows:int , spacing:Number , pieceClass:Class )
		{
			super( continer , cols , rows , spacing , pieceClass )
			isSwapping = false;
			isDropping = false;
		}
		
		override protected function setUpGrid():void
		{
			//创建方块循环 （随机到可用的序列
			while ( true )
			{
				//清空容器
				while ( continer.numChildren > 0 )
				{
					continer.removeChildAt( 0 );
				}
				//添加新方块
				for ( var j:int = 0 ; j < cols ; j++ )
				{
					for ( var k:int = 0 ; k < rows ; k++ )
					{
						addPiece( j , k );
					}
				}
				//检测是否有解
				if ( lookForMatches().length != 0 )
					continue;
				
				//是否可移动
				if ( lookForPossibles() == false )
					continue;
				break;
			}
		}
		
		/**
		 * 检测频率事件处理
		 * @param	e
		 */
		override protected function onTimer( e:TimerEvent ):void
		{
			var madeMove:Boolean = false;
			var p:Piece;
			for ( var row:int = 0 ; row < rows ; row++ )
			{
				for ( var col:int = 0 ; col < cols ; col++ )
				{
					p = grid[ col ][ row ];
					if ( p != null )
					{
						if ( p.y > p.row * spacing )
						{
							p.y -= 5;
							madeMove = true;
						}
						else if ( p.y < p.row * spacing )
						{
							p.y += 5;
							madeMove = true;
						}
						else if ( p.x > p.col * spacing )
						{
							p.x -= 5;
							madeMove = true;
						}
						else if ( p.x < p.col * spacing )
						{
							p.x += 5;
							madeMove = true;
						}
					}
				}
			}
			
			if ( !madeMove && isDropping )
			{
				//下降完成
				isDropping = false;
				findAndRemoveMatches();
			}
			else if ( !madeMove && isSwapping )
			{
				//移动完成
				isSwapping = false;
				findAndRemoveMatches();
			}
		}
		
		/**
		 * 开始
		 */
		override public function start():void
		{
			super.start();
			continer.addEventListener( MouseEvent.CLICK , onClick );
		}
		
		/**
		 * 停止
		 */
		override public function stop():void
		{
			super.stop();
			continer.removeEventListener( MouseEvent.CLICK , onClick );
		}
		
		/**
		 * 方块点击事件处理
		 * @param	e
		 */
		private function onClick( e:MouseEvent ):void
		{
			if ( e.target is Piece )
			{
				var p:Piece = e.target as Piece;
				trace( p );
				if ( firstPiece == null )
				{
					firstPiece = p;
					firstPiece.selected = true;
				}
				else if ( firstPiece == p )
				{
					p.selected = false;
					firstPiece = null;
				}
				else
				{
					//点击两个不同的方块
					firstPiece.selected = false;
					//行相同
					if (( firstPiece.col == p.col ) && ( Math.abs( firstPiece.row - p.row ) == 1 ) )
					{
						makeSwap( firstPiece , p );
						firstPiece = null;
					}
					//列相同
					else if (( firstPiece.row == p.row ) && ( Math.abs( firstPiece.col - p.col ) == 1 ) )
					{
						makeSwap( firstPiece , p );
						firstPiece = null;
					}
					else
					{
						firstPiece = p;
						firstPiece.selected = true;
					}
					
				}
			}
		}
		
		/**
		 * 获取横向匹配
		 * @param	col
		 * @param	row
		 * @return
		 */
		private function getMatchHoriz( col:int , row:int ):Array
		{
			var mat:Array = new Array( grid[ col ][ row ] );
			for ( var i:int = 1 ; col + i < cols ; i++ )
			{
				if ( grid[ col ][ row ].type == grid[ col + i ][ row ].type )
				{
					mat.push( grid[ col + i ][ row ] );
				}
				else
				{
					return mat;
				}
			}
			return mat;
		}
		
		/**
		 * 获取纵向匹配
		 * @param	col
		 * @param	row
		 * @return
		 */
		private function getMatchVert( col:int , row:int ):Array
		{
			var mat:Array = new Array( grid[ col ][ row ] );
			for ( var i:int = 1 ; row + i < rows ; i++ )
			{
				if ( grid[ col ][ row ].type == grid[ col ][ row + i ].type )
				{
					mat.push( grid[ col ][ row + i ] )
				}
				else
				{
					return mat;
				}
			}
			return mat;
		}
		
		/**
		 * 补充新方块
		 */
		private function addNewPieces():void
		{
			for ( var col:int = 0 ; col < cols ; col++ )
			{
				var missingPieces:int = 0;
				for ( var row:int = rows - 1 ; row >= 0 ; row-- )
				{
					if ( grid[ col ][ row ] == null )
					{
						addPiece( col , row ).y = -spacing * ++missingPieces;
						isDropping = true;
					}
				}
			}
		}
		
		/**
		 * 往下填充
		 * @param	p
		 */
		private function affectAbove( p:Piece ):void
		{
			for ( var row:int = p.row - 1 ; row >= 0 ; row-- )
			{
				if ( grid[ p.col ][ row ] != null )
				{
					grid[ p.col ][ row ].row++;
					grid[ p.col ][ row + 1 ] = grid[ p.col ][ row ];
					grid[ p.col ][ row ] = null;
				}
			}
		}
		
		/**
		 * 返回匹配方块
		 * @return
		 */
		public function lookForMatches():Array
		{
			var matches:Array = [];
			
			for ( var row:int = 0 ; row < rows ; row++ )
			{
				for ( var col:int = 0 ; col < cols - 2 ; col++ )
				{
					var mat:Array = getMatchHoriz( col , row );
					if ( mat.length > 2 )
					{
						matches.push( mat );
						col += mat.length - 1;
					}
				}
			}
			
			for ( col = 0 ; col < cols ; col++ )
			{
				for ( row = 0 ; row < rows - 2 ; row++ )
				{
					mat = getMatchVert( col , row );
					if ( mat.length > 2 )
					{
						matches.push( mat );
						row += mat.length - 1;
					}
				}
			}
			
			//trace( matches );
			return matches;
		}
		
		/**
		 * 移除匹配方块
		 */
		private function findAndRemoveMatches():void
		{
			var matches:Array = lookForMatches();
			for ( var i:int = 0 ; i < matches.length ; i++ )
			{
				for ( var j:int = 0 ; j < matches[ i ].length ; j++ )
				{
					if ( continer.contains( matches[ i ][ j ] ) )
					{
						affectAbove( removePiece( matches[ i ][ j ].col , matches[ i ][ j ].row ) );
					}
				}
			}
			
			//add new piece
			addNewPieces();
			
			//
			if ( matches.length == 0 && !lookForPossibles() )
			{
				gameOver();
			}
		}
		
		/**
		 * 游戏结束
		 */
		public function gameOver():void
		{
			EventProxy.broadcastEvent( new Match3Event( Match3Event.GAME_LOSE ) );
		}
		
		/**
		 * 测试换位置
		 * @param	p1
		 * @param	p2
		 */
		public function makeSwap( p1:Piece , p2:Piece ):void
		{
			swapPieces( p1 , p2 );
			if ( lookForMatches().length == 0 )
			{
				swapPieces( p1 , p2 );
			}
			else
			{
				isSwapping = true;
			}
		}
		
		/**
		 * 是否还有可移动方块
		 * @return
		 */
		public function lookForPossibles():Boolean
		{
			for ( var col:int = 0 ; col < 8 ; col++ )
			{
				for ( var row:int = 0 ; row < 8 ; row++ )
				{
					// horizontal possible, two plus one
					if ( matchPattern( col , row , [[ 1 , 0 ] ] , [[ -2 , 0 ] , [ -1 , -1 ] , [ -1 , 1 ] , [ 2 , -1 ] , [ 2 , 1 ] , [ 3 , 0 ] ] ) )
					{
						return true;
					}
					// horizontal possible, middle
					if ( matchPattern( col , row , [[ 2 , 0 ] ] , [[ 1 , -1 ] , [ 1 , 1 ] ] ) )
					{
						return true;
					}
					// vertical possible, two plus one
					if ( matchPattern( col , row , [[ 0 , 1 ] ] , [[ 0 , -2 ] , [ -1 , -1 ] , [ 1 , -1 ] , [ -1 , 2 ] , [ 1 , 2 ] , [ 0 , 3 ] ] ) )
					{
						return true;
					}
					// vertical possible, middle
					if ( matchPattern( col , row , [[ 0 , 2 ] ] , [[ -1 , 1 ] , [ 1 , 1 ] ] ) )
					{
						return true;
					}
				}
			}
			// no possible moves found
			return false;
		}
	}

}